Curso de ScriptVox Intermedirio - Aula 8 - Prof. Oswaldo Vernet - iNCE/UFRJ

Continuaremos, nesta oitava aula, a falar de listas na linguagem ScriptVox.

Vamos desenvolver um pequeno jogo utilizando listas. Ser um jogo de cartas, no
qual o usurio e o computador so adversrios. De incio, tiramos os coringas do baralho e
ficamos apenas com as 52 cartas tradicionais, sendo 13 de cada naipe. Cada carta tem um
valor em pontos: o "s" vale 1, as cartas numricas valem tantos pontos quanto o seu
prprio nmero, o valete vale 11, a dama vale 12 e o rei vale 13. O jogo  simples:
as cartas so embaralhadas no incio e dispostas num monte, colocado entre os dois
jogadores. Enquanto o monte de cartas no se esvaziar, os jogadores vo, alternadamente,
retirando a primeira carta do monte e o nmero de pontos de cada um vai sendo acumulado
de acordo com os valores das cartas que tiraram. Vence quem tiver mais pontos.

Todo problema em computao pode ter sua soluo facilitada ou dificultada, dependendo da
maneira que escolhemos para representar as informaes no programa. Em nosso caso, precisamos
manipular um baralho de 52 cartas e devemos ser capazes de realizar quatro operaes sobre 
este monte de cartas, que enumeramos a seguir: 

1. A primeira operao consiste em embaralhar o monte de cartas, colocando nele as 52
   cartas em uma ordem aleatria. Vamos cham-la de EMBARALHA MONTE.
   
2. A segunda operao consiste em verificar se o monte de cartas se esvaziou ou se ainda h
   cartas a serem retiradas pelos adversrios. Vamos cham-la de MONTE TEM CARTAS. Logo aps
   o embaralhamento,  claro, o monte ter as 52 cartas e no estar vazio. Mas conforme os
   usurios forem tirando cartas, o monte vai diminuindo at esvaziar-se. Precisamos saber
   quando o monte fica vazio porque isto significa o fim do jogo.
   
3. A terceira operao consiste em retirar do monte a carta de cima. Vamos cham-la de
   COMPRA CARTA. Durante o jogo, os dois adversrios vo alternadamente comprando cartas
   e acumulando pontos.

4. A quarta e ltima operao consiste em, dada uma carta, obter seu valor, ou seja, quantos
   pontos ela vale. Vamos cham-la de PONTUA CARTA.

O jogo consiste em executar a primeira operao uma vez apenas, s no incio, e depois
ficar repetindo as trs operaes seguintes, na ordem acima, at que o monte de cartas
se esvazie. O cuidado que precisamos ter  na hora de somar os pontos: obtido o valor da
carta, acumulamos uma vez nos pontos do usurio e, na vez seguinte, nos pontos do computador.
Como o usurio  sempre o primeiro a jogar (o computador  gentil), podemos dizer que,
nas vezes mpares, os pontos obtidos contaro para o usurio e, nas vezes pares, para o
computador.

Vamos criar uma funo para implementar cada uma das quatro operaes. A funo embaralha_monte
no recebe parmetros e produz o monte de cartas embaralhado. A funo monte_tem_cartas retorna 
VERDADEIRO (na verdade, o inteiro um) ou FALSO (na verdade, o inteiro zero), conforme ainda haja
cartas no monte ou no. A funo compra_carta simplesmente retira a primeira carta do monte,
retornando a carta que foi retirada. Finalmente, a funo pontua_carta retorna um nmero inteiro, 
que  a quantidade de pontos associada  carta recm comprada.

Uma primeira verso para o programa principal do jogo poderia ser a seguinte:

vez := 1
pontos_computador := 0
pontos_usurio := 0
embaralha_monte ()
enquanto monte_tem_cartas ()
	carta := compra_carta ()
	pontos := pontua_carta ()
	se vez = 0 
		pontos_computador := pontos_computador + pontos
		escreve "Seu adversrio comprou a carta " carta " e acumulou " pontos_computador " pontos at agora"
	seno
		pontos_usurio := pontos_usurio + pontos
		escreve "Voc comprou a carta " carta " e acumulou " pontos_usurio " pontos at agora"
	fim se
	vez := 1 - vez
fim enquanto

Observe como controlamos se  a vez do computador ou a vez do usurio. A varivel "vez" 
inicializada com o valor 1, significando que  vez do usurio. A ltima linha do bloco
do comando ENQUANTO contm a seguinte atribuio:

vez := 1 - vez

Esta atribuio tem o seguinte efeito: quando "vez" vale 1, a expresso um menos vez d zero e,
na prxima iterao, "vez" ter o valor zero; quando "vez" vale zero, a expresso um menos
vez d um e, na prxima iterao, "vez" ter o valor um. Entendeu? O valor da varivel "vez"
fica alternando entre 1 (usurio) e 0 (computador).

Um ponto importante deve ser observado antes de prosseguirmos. Por que optamos por criar uma
funo para cada uma das quatro operaes?  Por que simplesmente no implementamos tudo
no programa principal?

A grande vantagem de criar funes  que, no programa principal, estar programada apenas a 
essncia do jogo, chamando as quatro operaes da maneira correta e no momento correto.
Assim, o programa principal fica independente de como implementamos as operaes. 
Nesta aula, vamos usar listas, mas, em algum momento futuro, podemos mudar de ideia e usar
outro recurso para implementar as operaes. Da, bastar reescrever as quatro funes,
porque o programa principal no precisar ser alterado.

Muito bem. Poderemos partir agora para a implementao, escolhendo um modo de representar
o monte de cartas e escrevendo o cdigo correspondente a cada uma dessas quatro operaes.
J que estamos estudando listas, vamos tentar utiliz-las na nossa soluo: o monte de cartas
ser, ento, uma lista e dever estar armazenada em alguma varivel do script. Que tal
cham-la de "monte"?

A primeira pergunta : como embaralhar as cartas? A soluo matemtica para isto consiste 
em gerar aleatoriamente uma PERMUTAO das 52 cartas. 

Um mtodo simples para gerar uma permutao das 52 cartas consiste dos cinco passos seguintes: 

Passo 1. Disponha as cartas numa lista auxiliar em alguma ordem conhecida, por exemplo: todas
         as cartas de ouros, do s ao rei; depois todas as cartas de espadas, todas as cartas 
         de copas e, finalmente, todas as cartas de paus. Sempre do s ao rei dentro de cada naipe.
Passo 2. O monte de cartas embaralhado ser tambm uma lista, que comear vazia.
Passo 3. Escolha aleatoriamente uma posio vlida na lista auxiliar, ou seja, um nmero inteiro
         compreendido entre zero e o tamanho da lista auxiliar menos um (que corresponde 
		  ltima posio).
Passo 4. Retire da lista auxiliar a carta que ocupa a posio escolhida no passo 3.
Passo 5. Anexe ao monte de cartas a carta retirada da lista auxiliar no Passo 4.

Os passos 3, 4 e 5 devem ser repetidos at que acabem as cartas da lista auxiliar. A cada
repetio destes passos, tiramos uma carta da lista auxiliar e anexamos esta carta
ao monte. Portanto, quando a lista auxiliar ficar vazia, o monte de cartas conter todas 
as 52 cartas em alguma ordem desconhecida pelos usurios e, portanto, estar embaralhado.

Antes de analisar o exerccio, certifique-se de que compreendeu bem este algoritmo para gerar
permutaes. Na verdade, ele  mais geral do que parece e pode ser aplicado a uma lista qualquer
de objetos, no necessariamente cartas.  


EXERCCIO

Exerccio de avaliao (enviar para scriptvox@gmail.com at o meio-dia de 13 de fevereiro de 2012)

Neste exerccio, voc comear a implementar este jogo e, nas prximas aulas, ir completando a 
implementao.

Sua primeira tarefa ser, portanto, implementar a funo embaralha_monte. Antes disso, releia
o final da aula 7 (pode pular mame e filho conversando) para ter certeza de que entendeu 
direitinho as operaes sobre uma lista e como elas so implementadas em ScriptVox. 

Para facilitar, cada carta dever ser representada por uma cadeia formada da seguinte maneira: 
os dgitos que representam o valor numrico da carta seguidos da palavra "de" seguida do nome do naipe.
Assim, um trs de copas ser representado pela cadeia:

"3 de copas"

Uma dama de espadas seria:

"12 de espadas"

Um s de paus seria:

"1 de paus"

e assim por diante.

 claro que  feio chamar o "s" de um, a dama de "12", etc... Mas depois consertaremos isso.

Na funo embaralha_monte, todas as variveis devero ser locais, exceto a varivel "monte", 
que conter a lista com as cartas embaralhadas. Esta dever ser global. A lista auxiliar dever 
ser inicializada tendo como elementos as 52 cartas na ordem especificada no Passo 1 anteriormente. 
Quando a funo terminar, a lista auxiliar estar vazia e a lista "monte" global conter as 
cartas embaralhadas.

Uma maneira interessante de inicializar a lista auxiliar na ordem especificada no Passo 1 
 utilizar o comando "para", que  uma novidade da verso 6.0 do ScriptVox. Este comando 
implementa o PERCURSO em listas e, de modo semelhante a outros comandos de repetio, 
agrega linhas em um BLOCO. A sintaxe lembra a os comandos ENQUANTO e REPETE:

para varivel em lista
* BLOCO do comando "para"
fim para

Especificamos uma varivel, que  chamda de ITERADOR, e uma lista, que  chamada de DOMNIO. 
A ao do comando  a seguinte: o valor da varivel vai assumindo cada um dos elementos da 
lista, respeitando a ordem, ou seja, do primeiro at o ltimo; e, para cada valor, o bloco 
 executado. Assim, no exemplo:

lista := [ "uma", "lista", "pequena" ]
para x em lista
	escreve x
fim para

o valor da varivel "x", que  o iterador, ser, sucessivamente, as cadeias "uma", "lista" e 
"pequena", que so os trs elementos da lista especificada como domnio. Para cada um desses
valores, o bloco a ser executado consiste no comando ESCREVE x. Portanto, sero escritas na
tela, uma por linha, as cadeias "uma", "lista" e "pequena".

O nmero de vezes que o bloco do comando "para" ser repetido  a cardinalidade da lista. 
Se ela for vazia, o bloco no ser executado nenhuma vez; se a lista for unitria, 
o bloco ser executado uma vez; se ela contiver 100 elementos, o bloco ser executado 
100 vezes, e assim por diante.

Usando o comando "para", a lista auxiliar pode, ento, ser inicializada da seguinte forma:

	lista_auxiliar := []
	para naipe em [ "ouros", "espadas", "copas", "paus" ]
		para carta em [ 1 .. 13 ]
			lista_auxiliar[] := carta + " de " + naipe
		fim para
	fim para

Observou que existe um comando "para" mais interno, no bloco do comando "para" mais externo?
Como funciona isso?  simples: enquanto a varivel "naipe" (que  o iterador do comando "para"
mais externo) contiver o primeiro elemento da lista de naipes, que  "ouros", a varivel "carta"
(que  o iterador do comando "para" mais interno) assumir todos os valores inteiros de um a treze.
Assim, concatenando "carta", "de" e "naipe" teremos os nomes de todas as cartas, de um a treze,
do naipe de "ouros". O mesmo vai acontecer para "espadas", "copas" e "paus".

Voc se lembra de uma operao entre conjuntos denominada PRODUTO CARTESIANO?  A ideia era 
pegar cada elemento do primeiro conjunto e combinar com todos os elementos do segundo conjunto, 
formando pares. Conseguimos algo parecido aninhando comandos "para": um produto cartesiano
entre listas.
 
Observou o uso da faixa um ponto ponto treze para especificar a lista contendo os inteiros de 
um a treze?  Ela evita que tenhamos de escrever todos os nmeros de um a treze. Voc acha
bobagem, que no d trabalho nenhum escrever treze nmeros? Ento t: imagine se fosse de um a mil. 

Bem, isto apenas inicializa a lista auxiliar. A gerao do "monte" embaralhado fica por sua conta.
Use o comando ENQUANTO, anexando cada carta retirada aleatoriamente da lista auxiliar ao final do monte.
Lembre-se de usar o comando RANDOMIZA e de usar a funo RAND para gerar um nmero que seja uma posio 
vlida da lista auxiliar. Para saber se a lista auxiliar ainda contm cartas, compare-a com a
lista vazia, no teste do comando ENQUANTO. Assim:

enquanto lista_auxiliar <> []
* bloco do comando ENQUANTO
fim enquanto

Para testar a sua funo embaralha_monte, escreva um programa principal que chama a funo e depois
escreve o contedo da varivel "monte", que dever conter a lista de 52 cartas embaralhada. 

Bom estudo!

Oswaldo Vernet







